package com.hd123.rumba.qt.def;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.qt.collate.ICollateMgr;
import com.hd123.rumba.qt.run.Interpretor;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.util.HashMap2;

public class QueryDefinition {

  /**
   * 设置base, name和time
   * 
   * @param base
   * @param name
   */
  public void setFile(String base, String name) {
    File file = new File(base, name);
    this.setFile(file);
  }

  public void setFile(File file) {
    this.file = file;
    if (file.exists()) {
      Date time = new Date(file.lastModified());
      Calendar c = Calendar.getInstance();
      c.setTime(time);
      c.set(Calendar.MILLISECOND, 0);
      setTime(c.getTime());
    }
  }

  /**
   * 从文件中加载查询定义
   */
  public void load() throws BusinessException {
    try {
      FileInputStream fis = new FileInputStream(file);
      Query3Parser parser = new Query3Parser(fis);
      parser.schema_definition(this);
      initSg();
    } catch (Exception e) {
      throw new BusinessException(e);
    }
  }

  /**
   * 设置sg的第0行为条件名称, 其它行为criteria的内容
   */
  private void initSg() throws BusinessException {
    /** ***********预设条件的bug*********** */
    if (getChecks().getCaptions().size() > getCriterias().size())
      sg = new String[MAXROWCOUNT][getChecks().getCaptions().size()];
    else
      sg = new String[MAXROWCOUNT][getCriterias().size()];
    /** ********************************* */
    for (int i = 0; i < getCriterias().size(); ++i) {
      SQLCriteria c = (SQLCriteria) getCriterias().get(i);
      sg[0][i] = c.getDisplayName();
      if (c.getDefaultValue() != null)
        sg[1][i] = c.interpretDefaultValue(c.getDefaultValue());
      else {
        for (int j = 1; j <= c.getRights().size(); ++j) {
          sg[j][i] = (String) c.getRights().get(j - 1);
        }
      }
    }
  }

  /**
   * 把sg的内容设置到criterias中
   */
  public void setCriteria(String[][] sg) {
    SQLCriteria cr;
    if (criterias.size() > 0) {
      for (int i = 0; i < criterias.size(); ++i) {
        cr = (SQLCriteria) criterias.get(i);
        cr.getRights().clear();
      }
      int colcount = 0;
      for (int row = 1; row < MAXROWCOUNT; ++row)
        if (colcount < sg[row].length)
          colcount = sg[row].length;
      for (int row = 1; row < MAXROWCOUNT; ++row) {
        if (sg[row].length > 0) {
          for (int col = 0; col < colcount; ++col) {
            /** ***********预设条件的bug*********** */
            if (col >= criterias.size())
              continue;
            /** ********************************* */
            cr = (SQLCriteria) criterias.get(col);
            if (sg[row].length <= col)
              cr.getRights().add(null);
            else {
              if (cr.getPickNames().size() > 0 && sg[row][col] != null
                  && sg[row][col].trim().length() > 0) {
                int tempi = cr.getPickNames().indexOf(sg[row][col]);
                if (tempi >= 0)
                  cr.getRights().add(cr.getPickValues().get(tempi));
                else
                  // 修正了一个BUG!
                  cr.getRights().add(sg[row][col]);
              } else
                cr.getRights().add(sg[row][col]);
            }
          }
        }
      }
    }
    if (checks.getCheckeds().size() > 0) {
      for (int i = 0; i < checks.getCheckeds().size(); ++i)
        checks.getCheckeds().set(i, sg[MAXROWCOUNT - 1][i]);
    }
  }

  /**
   * 根据列标题返回列名
   * 
   * @param s
   * @return
   */
  public String getColumnByTitle(String title) throws BusinessException {
    // 如果title和某个列标题相符, 返回此列名
    for (int i = 0; i < columns.size(); ++i) {
      SQLColumn item = (SQLColumn) columns.get(i);
      if (title.equals(item.getTitle()))
        return item.getSQLSelectExpression();
    }
    return title;
  }

  /**
   * 根据列名返回列标题
   * 
   * @param name
   * @return
   */
  public String getTitleByColumn(String name) throws BusinessException {
    // 如果column和某个列名相符, 返回此列标题
    for (int i = 0; i < columns.size(); ++i) {
      SQLColumn item = (SQLColumn) columns.get(i);
      if (name.equalsIgnoreCase(item.getSQLSelectExpression(false).trim()))
        return item.getTitle();
    }
    return name;
  }

  public String translateTable(String input) throws BusinessException {
    return cm.getTableName(input);
  }

  /**
   * 将一个列名翻译成SQL语句中使用的标识符. 允许表达式.
   * 
   * @param s
   * @return
   */
  public String translateColumn(String input) throws BusinessException {
    char[] del = new char[] {
        ' ', '(', ')', ',', '+', '-', '*', '/', 0x0d, 0x0a, 0x09, '=', '|' };
    String token, alias, column;
    int i, k, u;
    List wordlist = new ArrayList();
    SQLTable t;
    boolean isConcat;
    // build word list

    token = "";
    isConcat = false;
    for (i = 0; i < input.length(); ++i) {
      if (inArray(input.getBytes()[i], del)) {
        if (input.getBytes()[i] == '|') {
          if (isConcat) {
            if (!"".equals(token))
              wordlist.add(token);
            wordlist.add("||");
            token = "";
            isConcat = false;
            continue;
          } else
            isConcat = true;
          continue;
        }
        if (!"".equals(token))
          wordlist.add(token);
        wordlist.add(input.substring(i, i + 1));
        token = "";
      } else
        token = token + input.substring(i, i + 1);
    }
    if (!"".equals(token))
      wordlist.add(token);
    // do translation:
    // tokens should be translated have form of alias.column
    for (i = 0; i < wordlist.size(); ++i) {
      k = ((String) wordlist.get(i)).lastIndexOf('.');
      if (k > 0) {
        alias = ((String) wordlist.get(i)).substring(0, k);
        column = ((String) wordlist.get(i)).substring(k + 1);
        for (u = 0; u < tables.size(); ++u) {
          t = (SQLTable) tables.get(u);
          if (t.getAlias().equals(alias)) {
            wordlist.set(i, t.getSQLAlias() + "."
                + cm.getFieldName(cm.getTableName(t.getName()), column));
            break;
          }
        }
      }
    }
    // rebuild
    StringBuffer sb = new StringBuffer();
    for (i = 0; i < wordlist.size(); ++i)
      sb.append(wordlist.get(i));
    return sb.toString();
  }

  private boolean inArray(byte c, char[] array) {
    for (int i = 0; i < array.length; ++i)
      if (c == array[i])
        return true;
    return false;
  }

  private ICollateMgr cm;

  /**
   * 返回可执行的SQL语句
   * 
   * @return
   * @throws IOException
   * @throws ParseException
   * @throws BusinessException
   */
  public String getSQLClause() throws IOException, ParseException, BusinessException {
    Interpretor interpretor = Interpretor.getInterpretor(sessionValues);

    StringBuffer sb = new StringBuffer();
    String clause = null;

    clause = getColumns().getSQLClause();
    if (clause != null) {
      sb.append(" select ");
      sb.append(clause);
    }
    clause = getTables().getSQLClause();
    if (clause != null) {
      sb.append("\n from ");
      sb.append(clause);
    }
    boolean bWhere = false;
    clause = interpretor.interpret(getJoins().getSQLClause());
    if (clause != null) {
      sb.append("\n where ");
      sb.append("(" + clause + ")");
      bWhere = true;
    }
    getCriterias().setQuery(this);
    clause = interpretor.interpret(getCriterias().getSQLClause(WHERECLAUSE));
    if (clause != null) {
      if (bWhere)
        sb.append("\n and ");
      else
        sb.append("\n where ");
      sb.append("(" + clause + ")");
      bWhere = true;
    }
    clause = getChecks().getSQLClause();
    if (clause != null) {
      if (bWhere)
        sb.append("\n and ");
      else
        sb.append("\n where ");
      sb.append(" (" + clause + ") ");
      bWhere = true;
    }
    clause = getGroups().getSQLClause();
    if (clause != null) {
      sb.append("\n group by ");
      sb.append(clause);
    }
    clause = getCriterias().getSQLClause(HAVINGCLAUSE);
    if (clause != null) {
      sb.append("\n having ");
      sb.append(" (" + clause + ") ");
    }
    clause = getUnions().getSQLClause();
    if (clause != null) {
      sb.append("\n union ");
      sb.append(clause);
    }
    clause = getOrders().getSQLClause();
    if (clause != null) {
      sb.append("\n order by ");
      sb.append(clause);
    }
    return sb.toString();
  }

  public String debugInfo() {
    StringBuffer sb = new StringBuffer();
    sb.append(getClass().getName() + "\n");
    sb.append("Base: " + file.getPath() + "\n");
    sb.append("Name: " + file.getName() + "\n");
    sb.append("Time: " + getTime() + "\n");
    sb.append("Version:" + getVersion() + "\n");
    sb.append("Remark: " + getRemark() + "\n");
    sb.append("Before: " + (getBeforeRunScript() == null ? null : getBeforeRunScript().debugInfo())
        + "\n");
    sb.append("After: " + (getAfterRunScript() == null ? null : getAfterRunScript().debugInfo())
        + "\n");
    sb.append("Tables: " + getTables().debugInfo() + "\n");
    sb.append("Joins: " + getJoins().debugInfo() + "\n");
    sb.append("Columns: " + getColumns().debugInfo() + "\n");
    sb.append("Groups: " + getGroups().debugInfo() + "\n");
    sb.append("Orders: " + getOrders().debugInfo() + "\n");
    sb.append("Criterias: " + getCriterias().debugInfo() + "\n");
    sb.append("Checks: " + getChecks().debugInfo() + "\n");
    sb.append("Unions: " + getUnions().debugInfo() + "\n");
    sb.append("NCriterias: " + getNcriterias().debugInfo() + "\n");
    sb.append("MultiQueries: " + getMultiQueries().debugInfo() + "\n");
    return sb.toString();
  }

  /** 查询文件 */
  private File file;
  /** 文件的最后修改时间 */
  private Date time;
  private String version;
  private String remark;
  private SQLScript beforeRunScript;
  private SQLScript afterRunScript;
  /** list of SQLTable */
  private SQLTableList tables = new SQLTableList();
  /** list of SQLJoin */
  private SQLJoinList joins = new SQLJoinList();
  /** list of SQLColumn */
  private SQLColumnList columns = new SQLColumnList();
  /** list of SQLGroup */
  private SQLGroupList groups = new SQLGroupList();
  /** list of SQLOrder */
  private SQLOrderList orders = new SQLOrderList();
  /** list of SQLCriteria */
  private SQLCriteriaList criterias = new SQLCriteriaList();
  /** list of SQLCheck */
  private SQLCheckList checks = new SQLCheckList();
  /** list of SQLUnion */
  private SQLUnionList unions = new SQLUnionList();
  /** list of SQLNCriteriaList */
  private SQLNCriteriaListList ncriterias = new SQLNCriteriaListList();
  /** list of SQLMultiQuery */
  private SQLMultiQueryList multiQueries = new SQLMultiQueryList(); //
  /** sg的第0行是条件名称, 内容从第1行第0列开始 */
  private String[][] sg;

  public QueryDefinition() throws BusinessException {
    NamingMgr nm = NamingMgr.getInstance();
    cm = (ICollateMgr) nm.lookupMgr(ICollateMgr.class);
    if (cm == null) {
      Logger.getLogger(QueryDefinition.class).warn(
          "没有找到ICollateMgr的实现类, 使用默认实现类com.hd123.rumba.qt.collate.CollateMgr");
      nm.registerManager("com.hd123.rumba.qt.collate.ICollateMgr",
          "com.hd123.rumba.qt.collate.CollateMgr");
      cm = (ICollateMgr) nm.lookupMgr(ICollateMgr.class);
      if (cm == null)
        throw new BusinessException("无法实例化ICollateMgr");
    }
  }

  public String[][] getSg() {
    return sg;
  }

  public void setSg(String[][] sg) {
    this.sg = sg;
  }

  public SQLMultiQueryList getMultiQueries() {
    return multiQueries;
  }

  public void setMultiQueries(SQLMultiQueryList multiQueries) {
    this.multiQueries = multiQueries;
  }

  public SQLScript getAfterRunScript() {
    return afterRunScript;
  }

  public void setAfterRunScript(SQLScript afterRunScript) {
    this.afterRunScript = afterRunScript;
  }

  public SQLScript getBeforeRunScript() {
    return beforeRunScript;
  }

  public void setBeforeRunScript(SQLScript beforeRunScript) {
    this.beforeRunScript = beforeRunScript;
  }

  public SQLCheckList getChecks() {
    return checks;
  }

  public void setChecks(SQLCheckList checks) {
    this.checks = checks;
  }

  public SQLColumnList getColumns() {
    return columns;
  }

  public void setColumns(SQLColumnList columns) {
    this.columns = columns;
  }

  public SQLCriteriaList getCriterias() {
    return criterias;
  }

  public void setCriterias(SQLCriteriaList criterias) {
    criterias.setQuery(this);
    this.criterias = criterias;
  }

  public SQLGroupList getGroups() {
    return groups;
  }

  public void setGroups(SQLGroupList groups) {
    this.groups = groups;
  }

  public SQLJoinList getJoins() {
    return joins;
  }

  public void setJoins(SQLJoinList joins) {
    this.joins = joins;
  }

  public SQLNCriteriaListList getNcriterias() {
    return ncriterias;
  }

  public void setNcriterias(SQLNCriteriaListList ncriterias) {
    this.ncriterias = ncriterias;
  }

  public SQLOrderList getOrders() {
    return orders;
  }

  public void setOrders(SQLOrderList orders) {
    this.orders = orders;
  }

  public String getRemark() {
    return remark;
  }

  public void setRemark(String remark) {
    this.remark = remark;
  }

  public SQLTableList getTables() {
    return tables;
  }

  public void setTables(SQLTableList tables) {
    this.tables = tables;
  }

  public SQLUnionList getUnions() {
    return unions;
  }

  public void setUnions(SQLUnionList unions) {
    this.unions = unions;
  }

  public String getVersion() {
    return version;
  }

  public void setVersion(String version) {
    this.version = version;
  }

  public Date getTime() {
    return time;
  }

  public void setTime(Date time) {
    this.time = time;
  }

  /** 调用SQLCriteria.getSQLClause时指明要返回的是WHER部分的 */
  public static final int WHERECLAUSE = 0;
  /** 调用SQLCriteria.getSQLClause时指明要返回的是HAVING部分的 */
  public static final int HAVINGCLAUSE = 1;
  /** sg的最大行数 */
  public static final int MAXROWCOUNT = 6;
  /** 数据库类型, 当DBMS=ORACLE时, 将*=转换成(+)=. 现在没有用, 也就是不会将*=转换成(+)= */
  public String DBMS;

  public static String[][] OPERATORS = new String[][] {
      {
          "=", "等于" }, {
          "BETWEEN", "在之间" }, {
          ">", "大于" }, {
          "<", "小于" }, {
          ">=", "大于等于" }, {
          "<=", "小于等于" }, {
          "<>", "不等于" }, {
          "NOT BETWEEN", "不在之间" }, {
          "<=", "不大于" }, {
          ">=", "不小于" }, {
          "LIKE", "类似于" }, {
          "NOT LIKE", "不同于" }, {
          "IN", "在之中" }, {
          "NOT IN", "不在之中" }, {
          "IS", "是否" }, {
          "*=", "右连接等于" } };
  public static String[][] AGGREGATORS = new String[][] {
      {
          "", "" }, {
          "SUM", "求和" }, {
          "MAX", "最大值" }, {
          "MIN", "最小值" }, {
          "AVG", "平均值" }, {
          "COUNT", "计数" }, {
          "COUNTDISTINCT", "去重计数" }, {
          "AGGREGATION", "聚集" } };
  public static String[][] SORTORDERS = new String[][] {
      {
          "ASC", "升序" }, {
          "DESC", "降序" } };
  public static final HashMap2 SORTORDERSVNM = new HashMap2().put2(SORTORDERS[0][0],
      SORTORDERS[0][1]).put2(SORTORDERS[1][0], SORTORDERS[1][1]);

  public String getOperatorName(String op) {
    for (int i = 0; i < OPERATORS.length; ++i)
      if (op.equals(OPERATORS[i][0]))
        return OPERATORS[i][1];
    return op;
  }

  private ISessionValues sessionValues;

  public void setSessionValues(ISessionValues sv) {
    sessionValues = sv;
  }

  public ISessionValues getSessionValues() {
    return sessionValues;
  }

  public File getFile() {
    return file;
  }

  public String getName() {
    return file.getName();
  }
}
